package com.amoyt.project.service.admin.impl;

import com.amoyt.project.config.redis.RedisCache;
import com.amoyt.project.config.redis.RedisIdWork;
import com.amoyt.project.constants.*;
import com.amoyt.project.domain.bo.LoginUser;
import com.amoyt.project.domain.dto.AdminLoginDto;
import com.amoyt.project.domain.dto.insert.AdminAddDto;
import com.amoyt.project.domain.dto.query.AdminPageQuery;
import com.amoyt.project.domain.dto.update.AdminUpdateDto;
import com.amoyt.project.domain.pojo.Role;
import com.amoyt.project.domain.pojo.User;
import com.amoyt.project.domain.pojo.UserRole;
import com.amoyt.project.domain.res.PageResult;
import com.amoyt.project.domain.res.Result;
import com.amoyt.project.domain.vo.AdminInfoVo;
import com.amoyt.project.domain.vo.LoginInfoVo;
import com.amoyt.project.domain.vo.PermissionVo;
import com.amoyt.project.enums.AdminLevelEnum;
import com.amoyt.project.exception.BusinessException;
import com.amoyt.project.exception.ExceptionUtil;
import com.amoyt.project.exception.enums.BusinessExceptionEnum;
import com.amoyt.project.mapper.RoleMapper;
import com.amoyt.project.mapper.UserMapper;
import com.amoyt.project.mapper.UserRoleMapper;
import com.amoyt.project.service.admin.AdminService;
import com.amoyt.project.utils.ConvertBeanUtils;
import com.amoyt.project.utils.JwtUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Date: 2025/8/10
 * @Time: 20:38
 * @Author: TQ_QT
 * @Description: 管理员服务实现类
 */
@Service
public class AdminServiceImpl implements AdminService {

    /**
     * 认证管理器
     */
    @Autowired
    private AuthenticationManager authenticationManager;
    /**
     * jwt工具类
     */
    @Autowired
    private JwtUtil jwtUtil;
    /**
     * redis缓存
     */
    @Autowired
    private RedisCache redisCache;

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private RedisIdWork redisIdWork;

    @Override
    public Result login(AdminLoginDto adminLoginDto) {
        //1.封装账号密码，权限等 TODO 封装权限信息
        //把登录时候的用户名与密码封装成一个UsernamePasswordAuthenticationToken对象
        UsernamePasswordAuthenticationToken authenticationToken
                = new UsernamePasswordAuthenticationToken(adminLoginDto.getUsername(), adminLoginDto.getPassword());

        //2.认证
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);

        //判断结果
        if (Objects.isNull(authenticate)) {
            throw new RuntimeException("登录失败！");
        }

        //3.认证成功 （拿到认证通过后的登录用户对象）
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();

        if (!loginUser.getUser().getUserType().equals(UserTypeConstants.ADMIN)){
            //删除缓存
            redisCache.deleteObject(RedisConstants.LOGIN_USER_KEY_PRE + loginUser.getUser().getUserId());
            //清理登录状态
            SecurityContextHolder.clearContext();
            return Result.error(ResponseConstants.NOT_ADMIN);
        }

        //4.用户编号，生成jwt
        String userId = loginUser.getUser().getUserId().toString();
        String jwt = jwtUtil.createJWT(userId);

        //5.信息存入redis
        redisCache.setCacheObject(RedisConstants.LOGIN_USER_KEY_PRE + userId, loginUser, RedisConstants.LOGIN_ADMIN_TTL, TimeUnit.HOURS);

        //6.返回结果
        // 获取第一个权限并去除ROLE_前缀 处理可能的空集合和权限格式问题
        String permission = loginUser.getAuthorities().stream()
                // 获取第一个元素（如果集合为空会返回空Optional）
                .findFirst()
                // 处理权限字符串
                .map(authority -> {
                    String authStr = authority.getAuthority();
                    // 只有以ROLE_开头时才截取，否则返回原字符串

                    return authStr.startsWith("ROLE_") ? authStr.substring(5) : authStr;
                })
                // 当没有权限时，返回默认值或抛出异常
                .orElse(""); // 或者使用 orElseThrow() 抛出异常
        LoginInfoVo loginInfoVo = LoginInfoVo.builder()
                .token(jwt)
                .role(permission)
                .build();

        return Result.success(ResponseConstants.SUCCESS_LOGIN,loginInfoVo);
    }

    @Override
    public Result logout() {
        //获取权限认证信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //获取用户信息
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        String userId = loginUser.getUser().getUserId();

        //移除登录状态
        redisCache.deleteObject(RedisConstants.LOGIN_USER_KEY_PRE + userId);

        //TODO 是否考虑存入logout，防止滥用token

        return Result.success(ResponseConstants.SUCCESS_LOGOUT,null);
    }

    @Override
    public Result getAdminInfo() {
        //获取当前登录id
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        AdminInfoVo adminInfoVo = ConvertBeanUtils.convert(loginUser.getUser(), AdminInfoVo.class);
        if(adminInfoVo == null){
            return Result.error(ResponseConstants.ERROR_USER_NOT_EXIST);
        }
        //封装返回
        return Result.success(adminInfoVo);
    }

    @Override
    public Result listAdmins(AdminPageQuery adminPageQuery) {
        //获取当前id的角色，分页查询下级角色，当前如果是
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        //查询线程第一个角色
        String permission = loginUser.getAuthorities().stream().findFirst().map(authority -> {
            String authStr = authority.getAuthority();
            return authStr.startsWith("ROLE_") ? authStr.substring(5) : authStr;
        }).orElse("");


        if (permission.isEmpty()){
            //无权限
            throw new BusinessException(BusinessExceptionEnum.PERMISSION_ERROR);
        }

        //获取下辖角色的列表
        List<String> roleList = AdminLevelEnum.getLowerLevelRole(permission);
        if (roleList.isEmpty()){
            //无下级角色
            return Result.success(PageResult.empty());
        }


        // 构建分页参数（当前页、每页条数）
        Page<AdminInfoVo> page = new Page<>(adminPageQuery.getPage(), adminPageQuery.getPageSize());
        // 调用 Mapper 方法，将 page 作为参数传入
        IPage<AdminInfoVo> userPage = userMapper.queryAdminList(page, roleList, adminPageQuery);

        //封装结果，返回
        PageResult pageResult = PageResult.builder()
                .total(userPage.getTotal())
                .records(userPage.getRecords())
                .build();

        return Result.success(pageResult);
    }

    @Override
    @Transactional
    public Result resetPassword(String userId) {
        //TODO 可以鉴权，是否是下级用户，暂时不做

        //查询
        User user = userMapper.selectById(userId);

        //加密
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encode = passwordEncoder.encode(user.getUserName()+"123456");

        User newUser = User.builder()
                .userId(userId)
                .password(encode)
                .build();
        userMapper.updateById(newUser);

        return Result.success(ResponseConstants.SUCCESS_RESET_PASSWORD);
    }

    @Override
    public Result delete(List<String> userIds) {
        //TODO 可以鉴权，是否是下级用户，暂时不做
        userMapper.deleteBatchIds(userIds);
        return Result.success();
    }

    @Override
    @Transactional
    public Result update(AdminUpdateDto adminUpdateDto) {
        //TODO 可以鉴权，是否是下级用户，暂时不做

        //copy
        User updateUser = ConvertBeanUtils.convert(adminUpdateDto, User.class);
        userMapper.updateById(updateUser);

        //是否修改权限
        String roleKey = adminUpdateDto.getRoleKey();
        if (roleKey != null && !roleKey.isEmpty()){

            //先查找原来的关联记录
            UserRole oldUserRole = userRoleMapper.selectOne(new QueryWrapper<UserRole>().eq("user_id", updateUser.getUserId()));

            //再找新的roleKey对应的权限id
            Role role = getRoleByRoleKey(roleKey);

            //新的关联记录
            UserRole newUserRole = UserRole.builder()
                    .userId(updateUser.getUserId())
                    .roleId(role.getRoleId())
                    .build();

            //构造原始查询条件
            QueryWrapper<UserRole> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id",oldUserRole.getUserId());
            queryWrapper.eq("role_id",oldUserRole.getRoleId());

            userRoleMapper.update(newUserRole,queryWrapper);
        }

        return Result.success(ResponseConstants.UPDATE_SUCCESS);
    }

    @Override
    @Transactional
    public Result updateOwn(AdminUpdateDto adminUpdateDto) {
        //获取当前的上下文
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        User updateUser = ConvertBeanUtils.convert(adminUpdateDto, User.class);

        //自己更新，修改缓存即可
        if(loginUser.getUser().getUserId().equals(updateUser.getUserId())){
            userMapper.updateById(updateUser);

            User user = userMapper.selectById(updateUser.getUserId());
            loginUser.setUser(user);
            System.out.println("更新缓存："+loginUser);

            //redis同步更新一下
            redisCache.updateObject(RedisConstants.LOGIN_USER_KEY_PRE + updateUser.getUserId(),loginUser);

        }else{
            throw ExceptionUtil.buildParamException("adminUpdateDto-userId-异常操作："+updateUser.getUserId());
        }

        return Result.success(ResponseConstants.UPDATE_SUCCESS);
    }

    @Transactional
    @Override
    public Result add(AdminAddDto adminAddDto) {
        //TODO 可以鉴权，是否是下级用户，暂时不做

        //获取当前用户
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        //获取当前用户权限第一个，并且删去角色前缀
        String roleKey = loginUser.getPermissions().get(0).substring(5);

        //查询权限是否正确 API查询
        Role role = getRoleByRoleKey(adminAddDto.getRoleKey());

        //校验权限是否分配正确
        if (!AdminLevelEnum.isLowerAdmin(roleKey , role.getRoleKey())){
            throw ExceptionUtil.buildParamException("adminAddDto-roleKey-权限分配错误："+role.getRoleKey());
        }

        // copy
        User addUser = ConvertBeanUtils.convert(adminAddDto, User.class);
        //处理数据
        addUser.setUserType(UserTypeConstants.ADMIN);
        addUser.setCreateTime(LocalDateTime.now());
        addUser.setCreateBy(loginUser.getUser().getUserId());
        addUser.setStatus(StatusConstants.STATUS_NORMAL);
        //生成id
        long adminId = redisIdWork.nextId("admin");
        String userId = IdConstants.USER_ID_PREFIX + adminId;

        addUser.setUserId(userId);

        //密码生成
        if(addUser.getPassword() == null || addUser.getPassword().equals("")){
            addUser.setPassword(InfoConstants.DEFAULT_PASSWORD);
        }
        String password = new BCryptPasswordEncoder().encode(addUser.getPassword());
        addUser.setPassword(password);

        //关联记录
        UserRole userRole = UserRole.builder()
                .roleId(role.getRoleId())
                        .userId(userId)
                                .build();

        //底层实现 API添加
        userMapper.insert(addUser);
        userRoleMapper.insert(userRole);

        //删除redis
        redisCache.deleteObject(RedisConstants.CACHE_USER_DATA);

        return Result.success(ResponseConstants.ADD_SUCCESS);
    }


    /**
     * 根据rolekey查询权限信息
     */
    private Role getRoleByRoleKey(String roleKey) {
        QueryWrapper<Role> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("role_key", roleKey);
        return roleMapper.selectOne(queryWrapper);
    }


    @Override
    public Result getLowerPermission() {
        //获取当前用户
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        //获取当前权限
        String permission = loginUser.getAuthorities().stream()
                // 获取第一个元素（如果集合为空会返回空Optional）
                .findFirst()
                // 处理权限字符串
                .map(authority -> {
                    String authStr = authority.getAuthority();
                    // 只有以ROLE_开头时才截取，否则返回原字符串
                    return authStr.startsWith("ROLE_") ? authStr.substring(5) : authStr;
                })
                // 当没有权限时，返回默认值或抛出异常
                .orElse("");

        //通过枚举返回下级权限列表
        List<PermissionVo> permissionVos = AdminLevelEnum.listLowerRole(permission);

        return Result.success(permissionVos);
    }
}
